#![no_std]
#![allow(static_mut_refs)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]

mod alloc_;
mod alloc_aligned;
mod atomic;
mod heap;
mod init;
mod internal;
mod os;
mod page;
mod page_queue;
mod segment;
mod stats;
mod types;
mod types_extra;

use core::alloc::{GlobalAlloc, Layout};

use alloc_::mi_free;
use alloc_aligned::{mi_malloc_aligned, mi_realloc_aligned, mi_zalloc_aligned};

pub struct MiMalloc;

unsafe impl GlobalAlloc for MiMalloc {
    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
        mi_malloc_aligned(layout.size(), layout.align())
    }

    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
        mi_zalloc_aligned(layout.size(), layout.align())
    }

    unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
        mi_free(ptr);
    }

    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
        mi_realloc_aligned(ptr, new_size, layout.align())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    fn check_zero(ptr: *mut u8, size: usize) {
        unsafe {
            for i in 0..size {
                assert_eq!(*ptr.add(i), 0)
            }
        }
    }

    #[test]
    fn run() {
        unsafe {
            let alloc = MiMalloc;
            for i in 3..20 {
                let size = 1 << i;
                let layout = Layout::from_size_align(size, 8).unwrap();
                let ptr = alloc.alloc_zeroed(layout);
                check_zero(ptr, size);
                alloc.dealloc(ptr, layout);
            }
        }
    }
}
